package risk.control.application.http;

import android.app.Activity;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;

import com.alibaba.fastjson2.JSON;

import org.apache.commons.codec.binary.Hex;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Dispatcher;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import risk.control.application.http.callback.HttpCallback;
import risk.control.application.utils.encrypt.CBC_Encryption;
import risk.control.application.utils.JsonUtils;
import risk.control.application.utils.LogUtils;
import risk.control.application.utils.UUIDUtils;

public class HttpPostClient {
    //秘钥
    public static final String secretKey = Hex.encodeHexString("kokL8G4RmNfV69cdcJ9dfnrlFGsLy6mH".getBytes());


//        private static final String baseUrl = "http://10.0.0.15:8081";
//    private static final String baseUrl = "http://172.26.2.97:8081";
    private static final String baseUrl = "http://47.107.93.234:8081";//阿里云测试

    private final OkHttpClient okHttpClient;
    private final Handler mainHandler;
    private final Map<Object, Call> callMap; // 用于管理Call对象


    // 私有化构造方法
    private HttpPostClient() {
        // 初始化OkHttpClient
        Dispatcher dispatcher = new Dispatcher();
        dispatcher.setMaxRequests(128);       // 最大并发请求数
        dispatcher.setMaxRequestsPerHost(32); // 每个主机最大并发数
        okHttpClient = new OkHttpClient.Builder()//
                .dispatcher(dispatcher)//
                .connectTimeout(30, TimeUnit.SECONDS)//
                .readTimeout(30, TimeUnit.SECONDS)//
                .writeTimeout(30, TimeUnit.SECONDS)//
                .build();
        // 主线程Handler
        mainHandler = new Handler(Looper.getMainLooper());
        // 线程安全的Call管理Map
        callMap = new ConcurrentHashMap<>();
    }

    // 静态内部类持有单例实例
    private static class Holder {
        private static final HttpPostClient INSTANCE = new HttpPostClient();
    }

    // 获取单例
    public static HttpPostClient getInstance() {
        return Holder.INSTANCE;
    }

    // post请求
    public String postData(Activity activity, String serviceName, String sessionId, HashMap<String, String> paramMap, HttpCallback callBack) {
        /*
         * 1、除了session接口外，其他接口的body全部要加密
         * 2、除了session接口外，其他接口的body增加时间戳参数
         * 3、除了session接口外，其他接口的header增加sessionId
         */
        Request request;
        if (serviceName.equals("000_000_000")) {
            String paramsString = JSON.toJSONString(paramMap);//map->json字符串
            RequestBody body = RequestBody.create(paramsString, MediaType.get("application/json; charset=UTF-8"));
            Request.Builder builder = new Request.Builder();
            builder.url(generateUrl(serviceName));//请链接
            builder.post(body);//请求体
            request = builder.build();//构建请求
        } else {
            paramMap.put("timestamp", String.valueOf(System.currentTimeMillis())); //增加时间戳参数
            paramMap.put("requestId", UUIDUtils.generate()); //增加时间唯一请求id
            String paramsString = JSON.toJSONString(paramMap);//map->json字符串
            String ciphertext = CBC_Encryption.encrypt(secretKey, paramsString);//json字符串再加密
            RequestBody body = RequestBody.create(ciphertext, MediaType.get("application/json; charset=UTF-8"));
            Request.Builder builder = new Request.Builder();
            builder.addHeader("sessionId", sessionId);//增加请求头
            builder.url(generateUrl(serviceName));//请链接
            builder.post(body);//请求体
            request = builder.build();//构建请求
        }
        Call call = okHttpClient.newCall(request);
        // 保存Call对象用于后续管理
        String requestId = UUID.randomUUID().toString();
        callMap.put(requestId, call);
        call.enqueue(new Callback() {
            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                callMap.remove(requestId);//移除call
                ResponseBody responseBody = response.body();
                if (responseBody == null) {
                    throw new IOException("responseBody为空");
                }
                int code = response.code();
                String message = response.message();
                String jsonString = responseBody.string();//加密数据
                if (code == 200) {
                    /*
                     * 服务端响应成功
                     * 是json数据-》服务器异常返回
                     * 不是json-》正常返回加密数据
                     */
                    String respData = JsonUtils.isJson(jsonString) ? jsonString : CBC_Encryption.decrypt(secretKey, jsonString);
                    LogUtils.e(serviceName + "--响应结果：" + respData);
                    if (activity != null && !activity.isDestroyed()) {
                        mainHandler.post(() -> {
                            callBack.onSuccess(respData);
                        });
                    }
                } else {
                    //响应失败
                    throw new IOException(message);
                }
            }

            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                callMap.remove(requestId);//移除call
                //异常如：服务端挂了，断网了，抛异常了
                if (activity != null && !activity.isDestroyed()) {
                    mainHandler.post(() -> {
                        callBack.onFailure(e.getMessage());
                    });
                }
            }
        });
        return requestId;
    }

    // 取消指定tag的请求
    public void cancel(String tag) {
        if (tag != null && !tag.isEmpty()) {
            Call call = callMap.get(tag);
            if (call != null && !call.isCanceled()) {
                call.cancel();
            }
            callMap.remove(tag);
        }
    }

    // 取消所有请求
    public void cancelAll() {
        for (Call call : callMap.values()) {
            if (call != null && !call.isCanceled()) {
                call.cancel();
            }
        }
        callMap.clear();
    }

    private static String generateUrl(String serviceName) {
        return baseUrl + "/risk/main/" + serviceName;
    }
}
